package main

import (
	"encoding/json"
	"math/rand"
	"os"
	"path/filepath"
	"regexp"

	"gitee.com/eeppee/ttyping/src/go_ttyping"
)

func init() {
	var ok bool
	var data string
	var home string

	if home, ok = os.LookupEnv("HOME"); !ok {
		die("Could not resolve home directory.")
	}

	if data, ok = os.LookupEnv("XDG_DATA_HOME"); ok {
		data = filepath.Join(data, "/ttyping")
	} else {
		data = filepath.Join(home, "/.local/share/ttyping")
	}

	os.MkdirAll(data, 0700)

	go_ttyping.FILE_STATE_DB = filepath.Join(data, ".db")
	go_ttyping.MISTAKE_DB = filepath.Join(data, ".errors")
}

func readValue(path string, o interface{}) error {
	b, err := os.ReadFile(path)

	if err != nil {
		return err
	}

	return json.Unmarshal(b, o)
}

func writeValue(path string, o interface{}) {
	b, err := json.Marshal(o)
	if err != nil {
		panic(err)
	}

	err = os.WriteFile(path, b, 0600)
	if err != nil {
		panic(err)
	}
}

func generateTestFromData(data []byte, raw bool, split bool) func() []segment {
	if raw {
		return func() []segment { return []segment{{string(data), ""}} }
	} else if split {
		paragraphs := getParagraphs(string(data))
		i := 0

		return func() []segment {
			if i < len(paragraphs) {
				p := paragraphs[i]
				i++
				return []segment{{p, ""}}
			} else {
				return nil
			}
		}
	} else {
		return func() []segment {
			var segments []segment

			for _, p := range getParagraphs(string(data)) {
				segments = append(segments, segment{p, ""})
			}

			return segments
		}
	}
}

func generateTestFromFile(path string, startParagraph int) func() []segment {
	var paragraphs []string
	var db map[string]int
	var err error

	if path, err = filepath.Abs(path); err != nil {
		panic(err)
	}

	if err := readValue(go_ttyping.FILE_STATE_DB, &db); err != nil {
		db = map[string]int{}
	}

	if startParagraph != -1 {
		db[path] = startParagraph
		writeValue(go_ttyping.FILE_STATE_DB, db)
	}

	idx := db[path] - 1

	if b, err := os.ReadFile(path); err != nil {
		die("Failed to read %s.", path)
	} else {
		paragraphs = getParagraphs(string(b))
	}

	return func() []segment {
		idx++
		db[path] = idx
		writeValue(go_ttyping.FILE_STATE_DB, db)

		if idx >= len(paragraphs) {
			return nil
		}

		return []segment{{paragraphs[idx], ""}}
	}
}

func generateWordTest(name string, n int, g int) func() []segment {
	var b []byte

	if b = readResource("db_words", name); b == nil {
		die("%s does not appear to be a valid word list. See '-list words' for a list of builtin word lists.", name)
	}

	words := regexp.MustCompile(`\s+`).Split(string(b), -1)

	return func() []segment {
		segments := make([]segment, g)
		for i := 0; i < g; i++ {
			segments[i] = segment{randomText(n, words), ""}
		}

		return segments
	}
}

func generateQuoteTest(name string) func() []segment {
	var quotes []segment

	if b := readResource("db_quotes", name); b == nil {
		die("%s does not appear to be a valid quote file. See '-list quotes' for a list of builtin quotes.", name)
	} else {
		err := json.Unmarshal(b, &quotes)
		if err != nil {
			die("Improperly formatted quote file: %v", err)
		}
	}

	return func() []segment {
		idx := rand.Int() % len(quotes)
		return quotes[idx : idx+1]
	}
}
